#include "unitconversionmanager.h"
#include "datamanager.h"
#include "map.h"
#include "utility.h"

namespace VrDataCore
{
	UnitConversionManager* UnitConversionManager::_unitConversionManager = NULL;

	UnitConversionManager::UnitConversionManager()
	{
		resetConversion();
	}

	UnitConversionManager::~UnitConversionManager()
	{}

	void UnitConversionManager::testReferenceUnitConversion()
	{
		QString ruc = DataManager::GetInstance().getCurrentMap()->getReferenceUnitConversion();
		if(ruc!=_referenceUnitConversion)
		{
			_referenceUnitConversion = ruc;
			//change map
			QStringList valuelist = _referenceUnitConversion.split(" ",QString::SkipEmptyParts);
			if(valuelist.size() == 8)
			{
				double minsx = valuelist.at(0).toDouble();
				double minsy = valuelist.at(1).toDouble();
				double maxsx = valuelist.at(2).toDouble();
				double maxsy = valuelist.at(3).toDouble();
				double minrx = valuelist.at(4).toDouble();
				double minry = valuelist.at(5).toDouble();
				double maxrx = valuelist.at(6).toDouble();
				double maxry = valuelist.at(7).toDouble();
				resetConversion();
				addConverReferencePointD(minsx,minsy,minrx,minry,false);
				addConverReferencePointD(maxsx,maxsy,maxrx,maxry,false);
			}
		}
	}

	UnitConversionManager& UnitConversionManager::GetInstance()
	{
		if(_unitConversionManager == NULL)
			_unitConversionManager = new UnitConversionManager();
		return *_unitConversionManager;
	}

	void UnitConversionManager::resetConversion()
	{
		_xReference = 1.0f;
		_yReference = 1.0f;
		_minSet._realWorldX = 0;
		_minSet._realWorldY = 0;
		_minSet._sceneWorldX = FLT_MAX;
		_minSet._sceneWorldY = FLT_MAX;
		_maxSet._realWorldX = 0;
		_maxSet._realWorldY = 0;
		_maxSet._sceneWorldX = -FLT_MAX;
		_maxSet._sceneWorldY = -FLT_MAX;
	}

	void UnitConversionManager::addConverReferencePointD(double sceneworldx,double sceneworldy,double realworldx,
		double realworldy,bool updatemap)
	{
		if(sceneworldx>_maxSet._sceneWorldX)
		{
			_maxSet._sceneWorldX = sceneworldx;
			_maxSet._realWorldX = realworldx;
		}
		if(sceneworldx<_minSet._sceneWorldX)
		{
			_minSet._sceneWorldX = sceneworldx;
			_minSet._realWorldX = realworldx;
		}
		if(sceneworldy>_maxSet._sceneWorldY)
		{
			_maxSet._sceneWorldY = sceneworldy;
			_maxSet._realWorldY = realworldy;
		}
		if(sceneworldy<_minSet._sceneWorldY)
		{
			_minSet._sceneWorldY = sceneworldy;
			_minSet._realWorldY = realworldy;
		}
		if(_minSet._sceneWorldX!=_maxSet._sceneWorldX && _minSet._sceneWorldY != _maxSet._sceneWorldY)
		{
			_xReference = abs((_minSet._realWorldX - _maxSet._realWorldX)/(_minSet._sceneWorldX - _maxSet._sceneWorldX));
			_yReference = abs((_minSet._realWorldY - _maxSet._realWorldY)/(_minSet._sceneWorldY - _maxSet._sceneWorldY));
		}
		if(updatemap)
			updateMap();
	}

	void UnitConversionManager::addConverReferencePointDMS(double sceneworldx,double sceneworldy,int realworldxd,int realworldxm,
		int realworldxds,int realworldyd,int realworldym,int realworldyds,bool updatemap)
	{
		if(sceneworldx>_maxSet._sceneWorldX)
		{
			_maxSet._sceneWorldX = sceneworldx;
			_maxSet._realWorldX = conversionDMS_TO_D(realworldxd,realworldxm,realworldxds);
		}
		if(sceneworldx<_minSet._sceneWorldX)
		{
			_minSet._sceneWorldX = sceneworldx;
			_minSet._realWorldX = conversionDMS_TO_D(realworldxd,realworldxm,realworldxds);
		}
		if(sceneworldy>_maxSet._sceneWorldY)
		{
			_maxSet._sceneWorldY = sceneworldy;
			_maxSet._realWorldY = conversionDMS_TO_D(realworldyd,realworldym,realworldyds);
		}
		if(sceneworldy<_minSet._sceneWorldY)
		{
			_minSet._sceneWorldY = sceneworldy;
			_minSet._realWorldY = conversionDMS_TO_D(realworldyd,realworldym,realworldyds);
		}
		if(_minSet._sceneWorldX!=_maxSet._sceneWorldX && _minSet._sceneWorldY != _maxSet._sceneWorldY)
		{
			_xReference = abs((_minSet._realWorldX - _maxSet._realWorldX)/(_minSet._sceneWorldX - _maxSet._sceneWorldX));
			_yReference = abs((_minSet._realWorldY - _maxSet._realWorldY)/(_minSet._sceneWorldY - _maxSet._sceneWorldY));
		}
		if(updatemap)
			updateMap();
	}

	void UnitConversionManager::addConverReferencePointDM(double sceneworldx,double sceneworldy,int realworldxd,double realworldxm
			,int realworldyd,double realworldym,bool updatemap)
	{
		if(sceneworldx>_maxSet._sceneWorldX)
		{
			_maxSet._sceneWorldX = sceneworldx;
			_maxSet._realWorldX = conversionDM_TO_D(realworldxd,realworldxm);
		}
		if(sceneworldx<_minSet._sceneWorldX)
		{
			_minSet._sceneWorldX = sceneworldx;
			_minSet._realWorldX = conversionDM_TO_D(realworldxd,realworldxm);
		}
		if(sceneworldy>_maxSet._sceneWorldY)
		{
			_maxSet._sceneWorldY = sceneworldy;
			_maxSet._realWorldY = conversionDM_TO_D(realworldyd,realworldym);
		}
		if(sceneworldy<_minSet._sceneWorldY)
		{
			_minSet._sceneWorldY = sceneworldy;
			_minSet._realWorldY = conversionDM_TO_D(realworldyd,realworldym);
		}
		if(_minSet._sceneWorldX!=_maxSet._sceneWorldX && _minSet._sceneWorldY != _maxSet._sceneWorldY)
		{
			_xReference = abs((_minSet._realWorldX - _maxSet._realWorldX)/(_minSet._sceneWorldX - _maxSet._sceneWorldX));
			_yReference = abs((_minSet._realWorldY - _maxSet._realWorldY)/(_minSet._sceneWorldY - _maxSet._sceneWorldY));
		}
		if(updatemap)
			updateMap();
	}

	void UnitConversionManager::updateMap()
	{
		_referenceUnitConversion = QString::number(_minSet._sceneWorldX,'g',15);
		_referenceUnitConversion.append(" ");
		_referenceUnitConversion.append(QString::number(_minSet._sceneWorldY,'g',15));
		_referenceUnitConversion.append(" ");
		_referenceUnitConversion.append(QString::number(_maxSet._sceneWorldX,'g',15));
		_referenceUnitConversion.append(" ");
		_referenceUnitConversion.append(QString::number(_maxSet._sceneWorldY,'g',15));
		_referenceUnitConversion.append(" ");
		_referenceUnitConversion.append(QString::number(_minSet._realWorldX,'g',15));
		_referenceUnitConversion.append(" ");
		_referenceUnitConversion.append(QString::number(_minSet._realWorldY,'g',15));
		_referenceUnitConversion.append(" ");
		_referenceUnitConversion.append(QString::number(_maxSet._realWorldX,'g',15));
		_referenceUnitConversion.append(" ");
		_referenceUnitConversion.append(QString::number(_maxSet._realWorldY,'g',15));
		VrDataCore::DataManager::GetInstance().getCurrentMap()->setReferenceUnitConversion(_referenceUnitConversion);
	}

	void UnitConversionManager::getAfterConverPointSTR(double sceneworldx,double sceneworldy,double& realworldx,double& realworldy)
	{
		testReferenceUnitConversion();
		realworldx = (sceneworldx - _minSet._sceneWorldX)*_xReference + _minSet._realWorldX;
		realworldy = (sceneworldy - _minSet._sceneWorldY)*_yReference + _minSet._realWorldY;
	}

	void UnitConversionManager::getAfterConverPointRTS(double& sceneworldx,double& sceneworldy,double realworldx,double realworldy)
	{
		testReferenceUnitConversion();
		sceneworldx = (realworldx - _minSet._realWorldX)/_xReference + _minSet._sceneWorldX;
		sceneworldy = (realworldy - _minSet._realWorldY)/_yReference + _minSet._sceneWorldY;
	}
}